package ex1;

public class Cell {
	private int UNEXPECTEDGEN = -1;
	private int currValue;
	private int prevValue;
	private int generation;
	private Synchronizer syncArr[];
	private ReadWriteLock cellLock;
	
	public Cell(int _value){
		currValue = _value;
		prevValue = UNEXPECTEDGEN;
		syncArr = new Synchronizer[8];
		cellLock = new ReadWriteLock();
	}
	
	/**
	 * Copy c'tor. Used to obtain current complex state of the cell. Read lock.
	 * @param _cell
	 */
	public Cell(Cell _cell){
		cellLock = new ReadWriteLock();
		cellLock.lockRead();
		generation = _cell.getGeneration();
		currValue = _cell.getValue(generation);
		prevValue = _cell.getValue(generation - 1);
		cellLock.unlockRead();
	}
	
	
	/**
	 * This function adds synchronizer to the cell.
	 * @param _sync
	 * @return True if succeeded, False in other case. 
	 */
	public boolean addSync(Synchronizer _sync){
		for(int i=0; i< syncArr.length; i++){
			if(syncArr[i] == null){
				syncArr[i] = _sync;
				return true;
			}
		} 
		return false;
	}
	
	/**
	 * This function notifies all the workers which work with this Shadow.
	 */
	private void notifyAllWorkers(){
		if(syncArr == null){
			throw new NullPointerException();
		}
		for(Synchronizer sync : syncArr){
			if(sync != null){
				sync.doNotify();
			}
		}
	}
	
	/**
	 * This function return value of sell in the generation.
	 * @param generation
	 * @return Value of cell in the generation. UNEXPECTEDGEN = -1 if the generation is out of boundaries.
	 */
	public synchronized int getValue(int _generation){
		if(_generation == generation){
			return currValue;
		}
		if(_generation == generation - 1){
			return prevValue;
		}
		return UNEXPECTEDGEN;
	}
	
	/**
	 * This function updates generation of the cell with given value. Write lock.
	 * @param _value New value of the cell.
	 * @throws InterruptedException 
	 */
	public synchronized void updateGeneration(int _value){
		cellLock.lockWrite();
		prevValue = currValue;
		currValue = _value;
		generation++;
		notifyAllWorkers();
		cellLock.unlockWrite();
	}

	/**
	 * 
	 * @return Generation of the cell.
	 */
	public synchronized int getGeneration(){
		return generation;
	}
	
	/**
	 * 
	 * @return Current value of the cell.
	 */
	public synchronized int getCurrValue(){
		cellLock.lockRead();
		int temp = currValue;
		cellLock.unlockRead();
		return temp;
	}
	
	public boolean isZeroCell(){
		return false;
	}
	
}
